package com.bean;
import java.io.Serializable;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.Date;
import java.util.List;
import java.util.Map;
import java.util.UUID;
import java.util.logging.Logger;

import javax.faces.application.FacesMessage;
import javax.faces.bean.ManagedBean;
import javax.faces.bean.SessionScoped;
import javax.faces.component.UIComponent;
import javax.faces.context.FacesContext;
import javax.faces.model.SelectItem;

import org.primefaces.event.ColumnResizeEvent;
import org.primefaces.event.DragDropEvent;
import org.primefaces.event.RowEditEvent;
import org.primefaces.event.SelectEvent;
import org.primefaces.event.ToggleEvent;
import org.primefaces.event.UnselectEvent;
import org.primefaces.model.DefaultTreeNode;
import org.primefaces.model.LazyDataModel;
import org.primefaces.model.TreeNode;

@ManagedBean
@SessionScoped
public class TableBean implements Serializable {
    
    private final static List<String> VALID_COLUMN_KEYS = Arrays.asList("model", "manufacturer", "year", "color");
        
        private final static Logger logger = Logger.getLogger(TableBean.class.getName());
        
        private final static String[] colors;
        
        private final static String[] manufacturers;
        
        private String theme;
    
    private String columnTemplate = "model manufacturer year";

        static {
                colors = new String[10];
                colors[0] = "Black";
                colors[1] = "White";
                colors[2] = "Green";
                colors[3] = "Red";
                colors[4] = "Blue";
                colors[5] = "Orange";
                colors[6] = "Silver";
                colors[7] = "Yellow";
                colors[8] = "Brown";
                colors[9] = "Maroon";
                
                manufacturers = new String[10];
                manufacturers[0] = "Mercedes";
                manufacturers[1] = "BMW";
                manufacturers[2] = "Volvo";
                manufacturers[3] = "Audi";
                manufacturers[4] = "Renault";
                manufacturers[5] = "Opel";
                manufacturers[6] = "Volkswagen";
                manufacturers[7] = "Chrysler";
                manufacturers[8] = "Ferrari";
                manufacturers[9] = "Ford";
        }

    private List<Car> filteredCars;
    
        private List<Car> cars;
        
        private List<Car> carsSmall;

    private List<Car> carsLarge;
    
    private List<Car> frozenCars;
        
        private Date date = new Date();
        
        private Car selectedCar;

        private Car[] selectedCars;

        private LazyDataModel<Car> lazyModel;



    private String columnName;

    private SelectItem[] manufacturerOptions;

    private List<Car> droppedCars;

    private List<ColumnModel> columns = new ArrayList<ColumnModel>();

    private boolean editMode;
    
  
    
    private CarDataModel smallCarsModel;
    
    private CarDataModel mediumCarsModel;
    
    private TreeNode availableColumns;

        public TableBean() {
                cars = new ArrayList<Car>();
                carsSmall = new ArrayList<Car>();
        carsLarge = new ArrayList<Car>();
        droppedCars = new ArrayList<Car>();
        frozenCars = new ArrayList<Car>();
                
                populateRandomCars(cars, 50);
                populateRandomCars(carsSmall, 9);
        populateRandomCars(carsLarge, 200);
        populateRandomCars(frozenCars, 2);
    

        createDynamicColumns();
        
        manufacturerOptions = createFilterOptions(manufacturers);
        
     
        
        smallCarsModel = new CarDataModel(carsSmall);
        mediumCarsModel = new CarDataModel(cars);
                
                
        
        createAvailableColumns();
        }
        
        public LazyDataModel<Car> getLazyModel() {
                return lazyModel;
        }
        
        public Car[] getSelectedCars() {
                return selectedCars;
        }
        public void setSelectedCars(Car[] selectedCars) {
                this.selectedCars = selectedCars;
        }
        
        public Car getSelectedCar() {
                return selectedCar;
        }

        public void setSelectedCar(Car selectedCar) {
                this.selectedCar = selectedCar;
        }

        public Date getDate() {
                return date;
        }
        public void setDate(Date date) {
                this.date = date;
        }

        private void populateRandomCars(List<Car> list, int size) {
                for(int i = 0 ; i < size ; i++)
                        list.add(new Car(getRandomModel(), getRandomYear(), getRandomManufacturer(), getRandomColor()));
        }
        
        private void populateLazyRandomCars(List<Car> list, int size) {
                for(int i = 0 ; i < size ; i++) {
                        list.add(new Car(getRandomModel(), getRandomYear(), getRandomManufacturer(), getRandomColor()));
                }
        }

    public List<Car> getFilteredCars() {
        return filteredCars;
    }

    public void setFilteredCars(List<Car> filteredCars) {
        this.filteredCars = filteredCars;
    }

        public List<Car> getCars() {
                return cars;
        }
        
        public List<Car> getCarsSmall() {
                return carsSmall;
        }

    public List<Car> getCarsLarge() {
                return carsLarge;
        }

    public List<Car> getFrozenCars() {
        return frozenCars;
    }
    
        private int getRandomYear() {
                return (int) (Math.random() * 50 + 1960);
        }
        
        private String getRandomColor() {
                return colors[(int) (Math.random() * 10)];
        }
        
        private String getRandomManufacturer() {
                return manufacturers[(int) (Math.random() * 10)];
        }
    
    public int getRandomPrice() {
                return (int) (Math.random() * 100000);
        }

    private int getRandomSale() {
                return (int) (Math.random() * 100000);
        }

    private int getRandomProfit() {
                return (int) (Math.random() * 100);
        }
        
        private String getRandomModel() {
                return UUID.randomUUID().toString().substring(0, 8);
        }
        
       
       
                
        public String getTheme() {
                return theme;
        }

        public void setTheme(String theme) {
                this.theme = theme;
        }
        
        public void save() {
                FacesContext.getCurrentInstance().addMessage(null, new FacesMessage(FacesMessage.SEVERITY_INFO, "Info", "Changes Saved"));
        }

    public void onRowSelect(SelectEvent event) {
        FacesMessage msg = new FacesMessage("Car Selected", ((Car) event.getObject()).getModel());

        FacesContext.getCurrentInstance().addMessage(null, msg);
    }

    public void onRowUnselect(UnselectEvent event) {
        FacesMessage msg = new FacesMessage("Car Unselected", ((Car) event.getObject()).getModel());

        FacesContext.getCurrentInstance().addMessage(null, msg);
    }
    
    public String onRowSelectNavigate(SelectEvent event) {
        FacesContext.getCurrentInstance().getExternalContext().getFlash().put("selectedCar", event.getObject());

        return "carDetail?faces-redirect=true";
    }

   

   


    public List<ColumnModel> getColumns() {
        return columns;
    }

    public String getColumnName() {
        return columnName;
    }

    public void setColumnName(String columnName) {
        this.columnName = columnName;
    }

    public String[] getManufacturers() {
        return manufacturers;
    }

    public String[] getColors() {
        return colors;
    }

    private SelectItem[] createFilterOptions(String[] data)  {
        SelectItem[] options = new SelectItem[data.length + 1];

        options[0] = new SelectItem("", "Select");
        for(int i = 0; i < data.length; i++) {
            options[i + 1] = new SelectItem(data[i], data[i]);
        }

        return options;
    }

    public SelectItem[] getManufacturerOptions() {
        return manufacturerOptions;
    }

    public void onCarDrop(DragDropEvent ddEvent) {
        Car car = ((Car) ddEvent.getData());

        droppedCars.add(car);
        carsSmall.remove(car);
    }

    public List<Car> getDroppedCars() {
        return droppedCars;
    }

    private void createAvailableColumns() {
        availableColumns = new DefaultTreeNode("Root", null);
        TreeNode root = new DefaultTreeNode("Columns", availableColumns);
        root.setExpanded(true);
                TreeNode model = new DefaultTreeNode("column", new ColumnModel("Model", "model"), root);
        TreeNode year = new DefaultTreeNode("column", new ColumnModel("Year", "year"), root);
        TreeNode manufacturer = new DefaultTreeNode("column", new ColumnModel("Manufacturer", "manufacturer"), root);
        TreeNode color = new DefaultTreeNode("column", new ColumnModel("Color", "color"), root);
    }
    
    static public class ColumnModel implements Serializable {

        private String header;
        private String property;

        public ColumnModel(String header, String property) {
            this.header = header;
            this.property = property;
        }

        public String getHeader() {
            return header;
        }

        public String getProperty() {
            return property;
        }
    }

    public void delete() {
        carsSmall.remove(selectedCar);
    }

    public boolean isEditMode() {
        return editMode;
    }

    public void setEditMode(boolean editMode) {
        this.editMode = editMode;
    }

    public String navigate() {
        return "home";
    }
    
    public void onEdit(RowEditEvent event) {
        FacesMessage msg = new FacesMessage("Car Edited", ((Car) event.getObject()).getModel());

        FacesContext.getCurrentInstance().addMessage(null, msg);
    }
    
    public void onCancel(RowEditEvent event) {
        FacesMessage msg = new FacesMessage("Car Cancelled", ((Car) event.getObject()).getModel());

        FacesContext.getCurrentInstance().addMessage(null, msg);
    }
    
    public void onResize(ColumnResizeEvent event) {
        FacesMessage msg = new FacesMessage("Column " + event.getColumn().getClientId() + " resized", "W:" + event.getWidth() + ", H:" + event.getHeight());

        FacesContext.getCurrentInstance().addMessage(null, msg);
    }
    
    
    
    public CarDataModel getMediumCarsModel() {
        return mediumCarsModel;
    }

    public CarDataModel getSmallCarsModel() {
        return smallCarsModel;
    }

    public TreeNode getAvailableColumns() {
        return availableColumns;
    }

    public void deleteCar() {
        carsSmall.remove(selectedCar);
    }

    public String getColumnTemplate() {
        return columnTemplate;
    }
    public void setColumnTemplate(String columnTemplate) {
        this.columnTemplate = columnTemplate;
    }
    
    public void updateColumns() {
        //reset table state
        UIComponent table = FacesContext.getCurrentInstance().getViewRoot().findComponent(":form:cars");
        table.setValueExpression("sortBy", null);
        
        //update columns
        createDynamicColumns();
    }
    
    public void createDynamicColumns() {
        String[] columnKeys = columnTemplate.split(" ");
        columns.clear();      
        
        for(String columnKey : columnKeys) {
            String key = columnKey.trim();
            
            if(VALID_COLUMN_KEYS.contains(key)) {
                columns.add(new ColumnModel(columnKey.toUpperCase(), columnKey));
            }
        }
    }
    
    public void onRowToggle(ToggleEvent event) {
        FacesMessage msg = new FacesMessage(FacesMessage.SEVERITY_INFO,
                                            "Row State " + event.getVisibility(),
                                            "Model:" + ((Car) event.getData()).getModel());
        
        FacesContext.getCurrentInstance().addMessage(null, msg);
    }
    
    public void treeToTable() {
        Map<String,String> params = FacesContext.getCurrentInstance().getExternalContext().getRequestParameterMap();
        String property = params.get("property");
        String droppedColumnId = params.get("droppedColumnId");
        String dropPos = params.get("dropPos");
        
        String[] droppedColumnTokens = droppedColumnId.split(":");
        int draggedColumnIndex = Integer.parseInt(droppedColumnTokens[droppedColumnTokens.length - 1]);
        int dropColumnIndex = draggedColumnIndex + Integer.parseInt(dropPos);
        
        //add to columns
        this.columns.add(dropColumnIndex, new ColumnModel(property.toUpperCase(), property));
        
        //remove from nodes
        TreeNode root = availableColumns.getChildren().get(0);
        for(TreeNode node : root.getChildren()) {
            ColumnModel model = (ColumnModel) node.getData();
            if(model.getProperty().equals(property)) {
                root.getChildren().remove(node);
                break;
            }
        }
    }
    
    public void tableToTree() {
        Map<String,String> params = FacesContext.getCurrentInstance().getExternalContext().getRequestParameterMap();
        int colIndex = Integer.parseInt(params.get("colIndex"));
        
        //remove from table
        ColumnModel model = this.columns.remove(colIndex);
        
        //add to nodes
        TreeNode property = new DefaultTreeNode("column", model, availableColumns.getChildren().get(0));
    }
    
    
}